template<class Drawer>
THeightmap<Drawer>::THeightmap() :
	_ncols(0), _nrows(0), _deep(1.0), _data(NULL)
{
}

template<class Drawer>
THeightmap<Drawer>::THeightmap(const float *data, int ncols, int nrows, float deep) :
	_ncols(ncols), _nrows(nrows), _deep(deep), _data(data)
{
	if(_data)
		create();
}

template<class Drawer>
THeightmap<Drawer>::~THeightmap()
{
}

template<class Drawer>
void THeightmap<Drawer>::load(const float *data, int ncols, int nrows, float deep)
{
	TMesh<Drawer>::clear();
	_ncols = ncols;
	_nrows = nrows;
	_deep = deep;
	_data = data;
	if(_data)
		create();
}

template<class Drawer>
void THeightmap<Drawer>::genNormals()
{
	if(!TMesh<Drawer>::model)
		return;
	float *vertices = TMesh<Drawer>::model->getVertices(), *normals = TMesh<Drawer>::model->getNormals();
	unsigned int *indices = TMesh<Drawer>::model->getIndices();
	unsigned int nbVertices = TMesh<Drawer>::model->getVBSize(), nbIndices = TMesh<Drawer>::model->getIBSize();
	if(!vertices || !indices)
		return;
	if(normals)
		delete[] normals;
	normals = new float[nbVertices];

	float v1[3], v2[3], v3[3], out[3];
	unsigned int aaux;
	for(unsigned int i=0; i<nbVertices; i++)
		normals[i] = 0;
	for(unsigned int i=0; i<nbIndices-2; i+=2)
    {
		aaux = indices[i];
		v1[0] = vertices[aaux*3];
		v1[1] = vertices[aaux*3+1];
		v1[2] = vertices[aaux*3+2];
		
		aaux = indices[i+1];
		v2[0] = vertices[aaux*3];
		v2[1] = vertices[aaux*3+1];
		v2[2] = vertices[aaux*3+2];

		aaux = indices[i+2];
		v3[0] = vertices[aaux*3];
		v3[1] = vertices[aaux*3+1];
		v3[2] = vertices[aaux*3+2];

		TMesh<Drawer>::createnormal(v1, v2, v3, out) ;
		TMesh<Drawer>::addnormal((normals+*(indices+i)*3),out);
		TMesh<Drawer>::addnormal((normals+*(indices+i+1)*3),out);
		TMesh<Drawer>::addnormal((normals+*(indices+i+2)*3),out);
    }
    TMesh<Drawer>::model->setNormals(normals, nbVertices);
    Drawer::addBuffer(GL_NORMAL_ARRAY, normals, nbVertices*sizeof(float), 3);
}

template<class Drawer>
void THeightmap<Drawer>::genTexCoords(int revert)
{
	float *texCoords = TMesh<Drawer>::model->getTexCoords();
	if(texCoords) delete[] texCoords;
	texCoords = new float[_nrows*_ncols*2];
	unsigned int k = 0;
	for(unsigned int i=0; i<_nrows; i++)
	{
		for(unsigned int j=0; j<_ncols*2; j+=2)
		{
			texCoords[k] = (float)(j/2)/_ncols;
			if(revert == TEXTURE_REVERT_Y || revert == TEXTURE_REVERT_XY) texCoords[k] = 1 - texCoords[k];
			k++;
			texCoords[k] = (float)(i)/_nrows;
			if(revert == TEXTURE_REVERT_X || revert == TEXTURE_REVERT_XY) texCoords[k] = 1 - texCoords[k];
			k++;
		}
	}
	TMesh<Drawer>::model->setTexCoords(texCoords, _nrows*_ncols*2);
	Drawer::addBuffer(GL_TEXTURE_COORD_ARRAY, texCoords, _nrows*_ncols*2*sizeof(float), 2);
}

template<class Drawer>
inline void THeightmap<Drawer>::draw()
{
    Renderer *rdr = Renderer::instance();

    rdr->pushMatrix();
	
	int vsize = TMesh<Drawer>::_textures.size();
	if(vsize > 0)
	{
		if(TMesh<Drawer>::_multiTex_ext)
		{
			for(int i=0; i<vsize; ++i)
				rdr->setMultiTexture(TMesh<Drawer>::_textures[i], i);
		}
		else
			rdr->setTexture(TMesh<Drawer>::_textures[0]);
	}

    rdr->scale(TMesh<Drawer>::_scale);
    rdr->translate(TMesh<Drawer>::_pos);
    rdr->rotate(TMesh<Drawer>::_angle, TMesh<Drawer>::_axes);

	Drawer::bind();
	for(unsigned int i=0; i<_nrows-1; i++)
		Drawer::drawRange(_ncols*2, i*_ncols*2);
	Drawer::unBind();

	if(vsize > 0)
	{
		if(TMesh<Drawer>::_multiTex_ext)
		{
			for(int i=0; i<vsize; ++i)
				rdr->setMultiTexture(NULL, i);
		}
		else
			rdr->setTexture(NULL);
	}

    rdr->popMatrix();
}

template<class Drawer>
void THeightmap<Drawer>::create()
{
	TMesh<Drawer>::clear();
	float *vertices = new float[_nrows*_ncols*3];
	for(unsigned int i=0; i<_nrows; i++)
	{
		for(unsigned int j=0; j<_ncols*3; j+=3)
		{
			vertices[i*_ncols*3+j] = i;
			vertices[i*_ncols*3+j+1] = j/3;
			vertices[i*_ncols*3+j+2] = _data[i*_ncols+j/3] * _deep;
		}
	}

	TMesh<Drawer>::model = new Model("heightmap", _nrows*_ncols*3, vertices);
	unsigned int *indices = new unsigned int[(_ncols)*(_nrows-1)*2];
	unsigned int k = 0;
	for(unsigned int i=0; i<_nrows-1; i++)
	{
		for(unsigned int j=0; j<_ncols; j++)
		{
			indices[k] = i*_ncols+j;
			k++;
			indices[k] = (i+1)*_ncols+j;
			k++;
		}
	}
	TMesh<Drawer>::model->setIndices(indices, (_ncols)*(_nrows-1)*2);
	Drawer::initialize(GL_TRIANGLE_STRIP);
	Drawer::addBuffer(GL_VERTEX_ARRAY, vertices, _nrows*_ncols*3*sizeof(float), 3);
	Drawer::addBuffer(GL_INDEX_ARRAY, indices, (_ncols)*(_nrows-1)*2*sizeof(unsigned int), 1);
	_data = NULL;
}
